//-----------------------------------------------------------------------------
// After Effects - Pixel Shader
//-----------------------------------------------------------------------------
#include "AfterEffectCommon.hlsl"


#if AFTER_EFFECT_ID == AE_TYPE_BLOOM_DOWNSAMPLE
// ------------------------------------------------------------------------------------------------
// BLOOM EFFECT - STEP 1 (DOWNSAMPLE)
// ------------------------------------------------------------------------------------------------
uniform sampler g_OrigSampler : register( s0 );
uniform float4	g_fHighLightThreshold;

	float luminance( float3 c )
	{
		return dot( c, float3( 0.3, 0.59, 0.11 ) );
	}

	float highlights( float3 c, float HighLightThreshold )
	{
		return smoothstep( HighLightThreshold, 1.0, luminance(c) );
	}

    float4 ProcessPixel( VSOUT _input )
    {
        float4 vColor;
 
        vColor = tex2D( g_OrigSampler, _input.TexCoord0.xy ) * 0.25;
        vColor += tex2D( g_OrigSampler, _input.TexCoord1.xy ) * 0.25;
        vColor += tex2D( g_OrigSampler, _input.TexCoord2.xy ) * 0.25;
        vColor += tex2D( g_OrigSampler, _input.TexCoord3.xy ) * 0.25;

        vColor.a = highlights(vColor.rgb, g_fHighLightThreshold.x);

        return vColor;
    }

#elif AFTER_EFFECT_ID == AE_TYPE_BLOOM_BLUR
// ------------------------------------------------------------------------------------------------
// BLOOM EFFECT - STEP 2 (BLUR H Dir / V Dir)
// ------------------------------------------------------------------------------------------------
uniform sampler g_OrigSampler : register( s0 );

    float4 ProcessPixel( VSOUT _input )
    {
		float4 c = 0;
		float weight7[7] = { 0.054441945, 0.1237355, 0.202502658, 0.238639794, 0.202502658, 0.1237355, 0.054441945 };

		c += tex2D( g_OrigSampler, _input.TexCoord0.xy ) * weight7[0];
		c += tex2D( g_OrigSampler, _input.TexCoord1.xy ) * weight7[1];
		c += tex2D( g_OrigSampler, _input.TexCoord2.xy ) * weight7[2];
		c += tex2D( g_OrigSampler, _input.TexCoord3.xy ) * weight7[3];
		c += tex2D( g_OrigSampler, _input.TexCoord4.xy ) * weight7[4];
		c += tex2D( g_OrigSampler, _input.TexCoord5.xy ) * weight7[5];
		c += tex2D( g_OrigSampler, _input.TexCoord6.xy ) * weight7[6];

        return c;
    }

#elif AFTER_EFFECT_ID == AE_TYPE_BLOOM_COMBINE
// ------------------------------------------------------------------------------------------------
// BLOOM EFFECT - STEP 3 (Combine to final buffer)
// ------------------------------------------------------------------------------------------------
uniform sampler g_OldSceneSampler	: register( s0 );
uniform sampler g_OrigSampler		: register( s1 );

uniform float4	g_fSceneIntensity;
uniform float4	g_fGlowIntensity;
uniform float4	g_fHighLightIntensity;


    float4 ProcessPixel( VSOUT _input )
    {
		float4 orig = tex2D( g_OldSceneSampler, _input.TexCoord0.xy );
		float4 blur = tex2D( g_OrigSampler, _input.TexCoord1.xy );

        return g_fSceneIntensity.x * orig + g_fGlowIntensity.x * blur + g_fHighLightIntensity.x * blur.a;
    }
#elif AFTER_EFFECT_ID == AE_TYPE_FOG_LAYERED
// ------------------------------------------------------------------------------------------------
// POST PROCESS FOG EFFECT - ( Height layered Fog )
// ------------------------------------------------------------------------------------------------
uniform sampler g_OldSceneSampler	: register( s0 );
uniform sampler g_DepthSampler		: register( s1 );

uniform float4x4 g_mInvWorldViewProj;
uniform float4	g_fCameraPos;
uniform float4	g_fFogLayerMinMax;
uniform float4	g_fFogColorTop;
uniform float4	g_fFogColorBottom;

    float4 ProcessPixel( VSOUT _input )
    {
		float4 orig = tex2D( g_OldSceneSampler, _input.TexCoord0.xy );
		float depth = clamp(1.0f - tex2D( g_DepthSampler, _input.TexCoord0.xy ).b, 0.0f, 1.0f);

		clip(depth-0.01f);

		// Get the screen position in world space (x,y,z,1)
		float4 pos = float4( _input.TexCoord0.zw, depth, 1.0f );
		pos = mul( pos, g_mInvWorldViewProj );
		pos /= pos.w;

		float h = abs( g_fCameraPos.z - pos.z );
		float u = length( g_fCameraPos.xyz - pos.xyz );

		float depthInfogLayer1 = clamp( (g_fCameraPos.z-g_fFogLayerMinMax.x)/(g_fFogLayerMinMax.y-g_fFogLayerMinMax.x), 0, 1 );
		float depthInfogLayer2 = clamp( (pos.z-g_fFogLayerMinMax.x)/(g_fFogLayerMinMax.y-g_fFogLayerMinMax.x), 0, 1 );

		float depthInfogLayer = abs(depthInfogLayer1 - depthInfogLayer2) * (g_fFogLayerMinMax.z + g_fFogLayerMinMax.w);
		depthInfogLayer += abs( (depthInfogLayer1*2-1)*(depthInfogLayer1*2-1) - (depthInfogLayer2*2-1)*(depthInfogLayer2*2-1) ) * 0.25 * (g_fFogLayerMinMax.w - g_fFogLayerMinMax.z);

		float fogDepth = u / h * depthInfogLayer;
		float fogBlendWeight = clamp(1-exp(-fogDepth), 0, 1);
		
		float4 BlendFogColor = lerp( g_fFogColorBottom, g_fFogColorTop, depthInfogLayer2 );

        return float4( orig.rgb*(1-fogBlendWeight) + BlendFogColor.rgb*fogBlendWeight, 1.0f);
	}
#elif AFTER_EFFECT_ID == AE_TYPE_FOG_LINEAR
// ------------------------------------------------------------------------------------------------
// POST PROCESS FOG EFFECT - ( LINEAR Fog )
// ------------------------------------------------------------------------------------------------
uniform sampler g_OldSceneSampler	: register( s0 );
uniform sampler g_DepthSampler		: register( s1 );

uniform float4x4 g_mInvWorldViewProj;
uniform float4	g_fCameraPos;
uniform float4	g_fFogLayerMinMax;
uniform float4	g_fFogColorWithDensity;

    float4 ProcessPixel( VSOUT _input )
    {
		float4 orig = tex2D( g_OldSceneSampler, _input.TexCoord0.xy );
		float depth = clamp(1.0f - tex2D( g_DepthSampler, _input.TexCoord0.xy ).b, 0.0f, 1.0f);

		clip(depth-0.01f);

		// Get the screen position in world space (x,y,z,1)
		float4 pos = float4( _input.TexCoord0.zw, depth, 1.0f );
		pos = mul( pos, g_mInvWorldViewProj );
		pos /= pos.w;

		float u = length( g_fCameraPos.xyz - pos.xyz );
		
		float fogBlendWeight = 0;

#if AFTER_EFFECT_SUB_TYPE == AE_TYPE_FOG_LINEAR_EXP		
		fogBlendWeight = clamp( 1 / exp(u * g_fFogLayerMinMax.z), 0, 1);
#elif AFTER_EFFECT_SUB_TYPE == AE_TYPE_FOG_LINEAR_EXP2		
		fogBlendWeight = clamp( 1 / exp(u*u * g_fFogLayerMinMax.z*g_fFogLayerMinMax.z), 0, 1);
#else
		fogBlendWeight = clamp( (g_fFogLayerMinMax.y - u) / (g_fFogLayerMinMax.y - g_fFogLayerMinMax.x), 0, 1);
#endif
		return float4( orig.rgb*fogBlendWeight + g_fFogColorWithDensity.rgb*(1-fogBlendWeight), 1.0f);
    }

#elif AFTER_EFFECT_ID == AE_TYPE_DOF  
	#if AFTER_EFFECT_SUB_TYPE == AE_TYPE_DOF_TWO_KERNEL_HEXAGONS
	
	uniform sampler g_SceneSampler		: register( s0 );
	uniform sampler g_DOFBlendSampler	: register( s1 );
	uniform float4	g_KernelArray[12];

		float4 ProcessPixel( VSOUT _input )
		{
			float4 Original = tex2D(g_SceneSampler, _input.TexCoord0.xy);
			float  OriginalBlur = tex2D(g_DOFBlendSampler, _input.TexCoord0.xy).r;
	        
			float3 Blurred = 0;
	    
			for(int i = 0; i < 6; i++)
			{
				// Lookup into the rendertarget based by offsetting the 
				// original UV by g_KernelArray[].
				float4 Current = tex2D(g_SceneSampler, _input.TexCoord0.xy + g_KernelArray[i].xy);
				float  CurrentBlur = tex2D(g_DOFBlendSampler, _input.TexCoord0.xy + g_KernelArray[i].xy).r;
				
				// Lerp between original rgb and the jitter rgb based on the alpha value
				Blurred += lerp(Original.rgb, Current.rgb, saturate(OriginalBlur * CurrentBlur));
			}
	           
			return float4(Blurred / 6, 1.0f);
		}
		
	#elif AFTER_EFFECT_SUB_TYPE == AE_TYPE_DOF_COMBINE
	
	uniform sampler g_SceneSampler		: register( s0 );
	uniform sampler g_DOFBlendSampler	: register( s1 );
	uniform sampler g_BlurSampler		: register( s2 );
	uniform float4 g_vScreenResolutionPS;		// x ->1/g_Samplerwidth y->1/g_Samplerheight z->1/g_BlurSamplerwidth w->1/g_BlurSamplerheight 
	float g_BlurRadiusScale;
	
		float4 ProcessPixel( VSOUT _input )
		{
			float2 poisson[8] = {
				float2( 0.0f,		 0.0f		),
				float2( 0.527837f,	-0.085868f	),
				float2(-0.040088f,   0.536087f	),
				float2(-0.670445f,  -0.179949f	),
				float2(-0.419418f,  -0.616039f	),
				float2( 0.440453f,  -0.639399f	),
				float2(-0.757088f,	 0.349334f	),
				float2( 0.574619f,	 0.685879f	)
			};
		
		
			float4 Original = tex2D(g_SceneSampler, _input.TexCoord0.xy + 0.5f * g_vScreenResolutionPS.xy);
			float  OriginalBlur = tex2D(g_DOFBlendSampler, _input.TexCoord0.xy+ 0.5f * g_vScreenResolutionPS.zw).r;
			
			float discRadiusBlurMap = g_BlurRadiusScale * OriginalBlur;
			
			float3 Blurred = 0;
			for(int i = 0; i < 8; i++)
			{
				float4 CurrentBlurRGB = tex2D(g_BlurSampler, _input.TexCoord0.xy + poisson[i] * discRadiusBlurMap * g_vScreenResolutionPS.zw + 0.5f * g_vScreenResolutionPS.zw);
				
				Blurred += lerp(Original.rgb, CurrentBlurRGB.rgb, OriginalBlur);
			}
			return float4(Blurred / 8, 1.0f);				
		}
	#endif
	
#elif AFTER_EFFECT_ID == AE_TYPE_FXAA

uniform sampler g_SceneSampler	: register( s0 );
uniform float4  g_vScreenResolutionPS;		// x ->width y->height z->1/width w->1/height 

    float4 ProcessPixel( VSOUT _input )
    {
		#define FXAA_REDUCE_MIN		(1.0/128.0)
		#define FXAA_REDUCE_MUL		(1.0/8.0)
		#define FXAA_SPAN_MAX		8.0

		float3 rgbNW = tex2D(g_SceneSampler, _input.TexCoord0.zw).rgb;
		float3 rgbNE = tex2D(g_SceneSampler, _input.TexCoord0.zw + float2(1,0) * g_vScreenResolutionPS.zw).rgb;
		float3 rgbSW = tex2D(g_SceneSampler, _input.TexCoord0.zw + float2(0,1) * g_vScreenResolutionPS.zw).rgb;
		float3 rgbSE = tex2D(g_SceneSampler, _input.TexCoord0.zw + float2(1,1) * g_vScreenResolutionPS.zw).rgb;
		float3 rgbM = tex2D(g_SceneSampler, _input.TexCoord0.xy).rgb;

		float3 luma = float3(0.299, 0.587, 0.114);
		float lumaNW = dot(rgbNW, luma);
		float lumaNE = dot(rgbNE, luma);
		float lumaSW = dot(rgbSW, luma);
		float lumaSE = dot(rgbSE, luma);
		float lumaM = dot(rgbM, luma);
		
		float lumaMin = min( lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)) );
		float lumaMax = max( lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)) );

		float2 dir;
		dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
		dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));

		float dirReduce = max( (lumaNW + lumaNE + lumaSW + lumaSE) * (0.25*FXAA_REDUCE_MUL), FXAA_REDUCE_MIN );
		float rcpDirMin = 1.0f / ( min(abs(dir.x),abs(dir.y)) + dirReduce );
		dir = min( float2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max( float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir*rcpDirMin ) ) * g_vScreenResolutionPS.zw;

		float3 rgbA = (1.0/2.0) * (tex2D(g_SceneSampler, _input.TexCoord0.xy + dir*(1.0/3.0-0.5)).rgb + tex2D(g_SceneSampler, _input.TexCoord0.xy + dir*(2.0/3.0-0.5)).rgb);
		float3 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (tex2D(g_SceneSampler, _input.TexCoord0.xy + dir*(0.0/3.0-0.5)).rgb + tex2D(g_SceneSampler, _input.TexCoord0.xy + dir*(3.0/3.0-0.5)).rgb);
	
		float lumaB = dot(rgbB, luma);

		if( (lumaB < lumaMin) || (lumaB > lumaMax) )
			return float4( rgbA, 1.0f );
		return float4( rgbB, 1.0f );	
	}
	
#elif AFTER_EFFECT_ID == AE_TYPE_HeadLight
// ------------------------------------------------------------------------------------------------
// POST PROCESS HeadLight ( FullScreen Black Circle Ring )
// ------------------------------------------------------------------------------------------------
uniform sampler g_SceneSampler			: register( s0 );
uniform sampler g_HeadLightSampler		: register( s1 );

    float4 ProcessPixel( VSOUT _input )
    {
		float3 FinalColor = tex2D( g_SceneSampler, _input.TexCoord0.xy ).rgb * tex2D( g_HeadLightSampler, _input.TexCoord1.xy ).rgb;
        return float4( FinalColor.rgb, 1.0f);
    }
    
#elif AFTER_EFFECT_ID == AE_TYPE_Gamma    
// ------------------------------------------------------------------------------------------------
// Gamma Correction ( FullScreen Post Process color Correction )
// ------------------------------------------------------------------------------------------------
uniform sampler g_TextureSampler0 : register( s0 );
uniform sampler g_TextureSampler1 : register( s1 );

uniform float  g_fGammaScale;

    float4 ProcessPixel( VSOUT _input )
    {
		float3 color = pow( tex2D(g_TextureSampler0, _input.TexCoord0).rgb, 2.2f );

		color.r = tex1D(g_TextureSampler1, color.r).r;
		color.g = tex1D(g_TextureSampler1, color.g).g;
		color.b = tex1D(g_TextureSampler1, color.b).b;

		return float4(pow(color.rgb, g_fGammaScale / 2.2f) , 1.0f);
    }
        
#else
// ------------------------------------------------------------------------------------------------
// DEFAULT
// ------------------------------------------------------------------------------------------------
    float4 ProcessPixel( VSOUT _input )
    {
        return float4( 0.0f, 0.0f, 0.0f, 0.0f );
    }

#endif
